function WebGLBoard(gl)
{
	var boardShader =
        new Shader(gl,
		"const vec4 lightpos = vec4(0.0, 5.0, 0.0, 1.0); "+
        "attribute vec2 position;" +
        "uniform mat4 projection; uniform mat4 view; uniform mat4 model;" +
        "varying vec3 nor; " + 
        "varying vec4 pos; " + 
        "varying vec4 lightViewSpace; " + 
        "varying vec2 uv; " + 
        "void main() {"+
        "   uv = position;"+
        "   lightViewSpace = view * lightpos;"+
        "   nor = normalize(view * model * vec4(0.0, 1.0, 0.0, 0.0)).xyz;"+
        "   pos = view * model * vec4(position.x, 0, position.y, 1);"+
        "   gl_Position = projection * pos;"+
        "}"
        ,
        "uniform vec4 color;"+
        "uniform vec4 borderColor;" + 
        "varying vec3 nor; " + 
        "varying vec4 pos; " + 
        "varying vec4 lightViewSpace; " + 
        "varying vec2 uv;"+
		"const vec3 attenuation  = vec3(1.0, 0.010, 0.005);"+
        "void main() {"+
        "   const float margin = 0.05;"+
        "   const float border = 0.1 + margin;"+
        "   if(uv.x < margin || uv.x > 1.0 - margin || uv.y < margin || uv.y > 1.0 - margin) discard;"+
        "   vec4 col = vec4(1.0, 0.0, 1.0, 1.0);"+
        "   if(uv.x < border || uv.x > 1.0 - border || uv.y < border || uv.y > 1.0 - border) col = borderColor;"+
        "   else col = color;"+

		"   vec4 pos2light = lightViewSpace - pos;" + 
		"   float dist = length(pos2light);" + 
		"   vec4 light = normalize(pos2light);" +
		"   float attfactor = 1.0 / (attenuation.x + attenuation.y * dist + attenuation.z * dist * dist);"+
		"   float diffuse = attfactor * max(0.0, dot(nor, light.xyz));"+
		"   float specular = attfactor * pow(max(0.0, dot(-reflect(light.xyz, nor), normalize(-pos).xyz)), 32.0);"+
		"   gl_FragColor = vec4(((0.4 + diffuse) * col.xyz + specular * vec3(0.7, 0.7, 0.7)), color.w);"+

        "}"
        );
	var bordercolors = undefined;
	this.width = undefined;
	this.height = undefined;
	this.colors = undefined;
	
	var vertexData = new WebGLFloatArray([
		// Position XZ
		0.0,	0.0,
		0.0,	1.0,
		1.0,	0.0,
		1.0,	1.0
		]);
    
	var vbo = gl.createBuffer();
	checkWebGLError(gl);
	gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
	checkWebGLError(gl);
	
	gl.bufferData(gl.ARRAY_BUFFER, vertexData, gl.STATIC_DRAW);
	checkWebGLError(gl);
	
	this.update = function(player, game, fsm)
	{
		var hierarkia = game.hierarkia();
		this.width = game.info.width;
		this.height = game.info.height;
		this.colors = new Array(this.width * this.height);
		bordercolors = new Array(this.width * this.height);
		
		for (var x = 0; x < this.width; ++x)
		{
			for (var y = 0; y < this.height; ++y)
			{
				var index = x + y * this.width;
				bordercolors[index] = [0.95, 0.95, 0.95, 0.4];
				
				var color = [0.75, 0.7, 0.75, 0.6];
				var home = hierarkia.homezone(x, y);
				
				if(home == Side.RED) color = [0.9, 0.3, 0.1, 0.6];
				else if(home == Side.BLUE) color = [0.1, 0.3, 0.9, 0.6];
				
				var cell = hierarkia.get(x, y);
				
				if(cell && hierarkia.canMove(x, y) && cell.side == game.currentSide())
				{
					bordercolors[index] = [1.0, 1.0, 0.0, 0.8];
				}
				
				if(fsm.state == UIState.MOVING)
				{
					if(hierarkia.canMoveTo(fsm.from[0], fsm.from[1], x, y))
					{
						cell = hierarkia.get(fsm.from[0], fsm.from[1]);
						if (cell)
						{
							if (cell.side == Side.RED) bordercolors[index] = [1.0, 0.0, 0.0, 0.8];
							else bordercolors[index] = [0.0, 0.0, 1.0, 0.8];
						} 
					}
				}
				
				this.colors[index] = color;
			}
		}
	}
	
	this.draw = function(projection, view, mouseover)
	{
	    if(!this.width || !this.height || !this.colors) return;
	
		gl.useProgram(boardShader.program);
		checkWebGLError(gl);
		
		var projLoc = gl.getUniformLocation(boardShader.program, "projection");
		checkWebGLError(gl);
		gl.uniformMatrix4fv(projLoc, true, projection);	
		checkWebGLError(gl);
		
		var viewLoc = gl.getUniformLocation(boardShader.program, "view");
		gl.uniformMatrix4fv(viewLoc, true, view);
		checkWebGLError(gl);
		
		var modelLoc = gl.getUniformLocation(boardShader.program, "model");
		checkWebGLError(gl);
		
		var colorLoc = gl.getUniformLocation(boardShader.program, "color")
		checkWebGLError(gl);

		var borderLoc = gl.getUniformLocation(boardShader.program, "borderColor")
		checkWebGLError(gl);
		
		var positionLoc = gl.getAttribLocation(boardShader.program, "position");
		checkWebGLError(gl);
		gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
		checkWebGLError(gl);
        gl.vertexAttribPointer(positionLoc, 2, gl.FLOAT, gl.FALSE, 0, 0)
		checkWebGLError(gl);
        gl.enableVertexAttribArray(positionLoc);
		checkWebGLError(gl);
		
		var modelMatrix = 
		[
			1, 0, 0, 0,
			0, 1, 0, 0,
			0, 0, 1, 0,
			0, 0, 0, 1
		];
		
		for(var x = 0; x < this.width; ++x)
		{
			for(var y = 0; y < this.height; ++y)
			{
				var index = x + y * this.width;
				modelMatrix[3] = x - this.width / 2.0;
				modelMatrix[11] = y - this.height / 2.0;
				gl.uniformMatrix4fv(modelLoc, true, modelMatrix);
				checkWebGLError(gl);
		
				var color = undefined;
				
				if (mouseover && mouseover[0] == x && mouseover[1] == y) 
				{
					color = [0.2, 0.7, 0.4, 0.8];
            	}
				else
				{
					color = this.colors[index];
				}
				
				var r = color[0], g = color[1], b = color[2], a = color[3];
				gl.uniform4f(colorLoc, r, g, b, a);
				checkWebGLError(gl);
				
				var bordercolor = bordercolors[index];
				
                gl.uniform4f(borderLoc, bordercolor[0], bordercolor[1], bordercolor[2], bordercolor[3]);
				checkWebGLError(gl);

				gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
				checkWebGLError(gl);
			}
		}
		
        gl.disableVertexAttribArray(positionLoc);
	}    
}

